package com.mytx.search.controller;


import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mytx.common.annotation.SerializedField;
import com.mytx.common.constant.Constant;
import com.mytx.common.pojo.CommonResult;
import com.mytx.mapper.CommentMapper;
import com.mytx.mapper.ForwardMapper;
import com.mytx.mapper.TopicMapper;
import com.mytx.pojo.Comment;
import com.mytx.pojo.CommentExample;
import com.mytx.pojo.Topic;
import com.mytx.search.CommentConstant;
import com.mytx.search.config.EsSearchClient;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@RestController
public class CommentController {
    private static final Logger logger = LoggerFactory.getLogger(CommentController.class);
    @Autowired
    private CommentMapper commentMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    TopicMapper topicMapper;
    @Autowired
    EsSearchClient searchClient;

    @Autowired
    ForwardMapper forwardMapper;

    @Autowired
    private HttpServletRequest request;
    // 参数无效
    String PARAM_INVALID = "8001";
    String NO_PRAISE = "0";
    String HAD_PRAISE = "1";

    @RequestMapping(value = "/comment/create", method = RequestMethod.POST)
    @SerializedField(encrypt = false)
    public CommonResult create(@RequestBody Comment comment) {
        // logger.info("create:创建评论" + comment.getFromUid());
        comment.setId(getUUID());
        String topicId = comment.getTopicId();
        comment.setCreated(new Date());
        commentMapper.insertSelective(comment);
//        //检查评论数量在redis是否存在
//        String result = redisTemplate.opsForValue().getTopicById("COMMENT_SIZE:" + topicId);
//        //返回 -1 表面没有缓存了
//        if (result.equals("-1")) {
//            //
//        }

        //主题ID，作为key,在redis中存储该主题的评论数量，
        //  redisTemplate.opsForValue().increment(Constant.COMMENT_SIZE + topicId, 1);
        updateCommentSize(topicId);


        return CommonResult.ok(comment.getId());
    }

    /**
     * 对转发进行评论
     *
     * @param comment
     * @return
     */
    @Transactional
    @RequestMapping(value = "/comment/createComment_v1", method = RequestMethod.POST)
    @SerializedField(encrypt = false)
    public CommonResult createComment_v1(@RequestBody Comment comment) {
        comment.setId(getUUID());
        comment.setCreated(new Date());
        commentMapper.insertSelective(comment);
        forwardMapper.incrementCommentSize(comment.getTopicId());
        return CommonResult.ok(comment.getId());
    }

    /**
     * 同时更新mysql .es 中的主题的评论数量
     *
     * @param topicId
     */
    private void updateCommentSize(String topicId) {
        //增加主题的评论数量
        int totalCommentSize = topicMapper.incrementCommentSize(topicId);
        //更新ES 中的 评论数量

        Topic updateTopic = new Topic();
        updateTopic.setCommentSize(totalCommentSize);
        UpdateRequest request = new UpdateRequest("topics", "topic", topicId);
        request.doc(JSONObject.toJSONString(updateTopic), XContentType.JSON);
        UpdateResponse response = searchClient.update(request);
        if (response == null || response.getResult() != DocWriteResponse.Result.UPDATED) {
            logger.error("create:更新es 中的评论数量出错" + response.getResult());
        }
    }

    @SuppressWarnings("Duplicates")
    @RequestMapping(value = "/comment/createChildComment", method = RequestMethod.POST)
    @SerializedField(encrypt = false)
    public CommonResult createChildComment(@RequestBody Comment comment) {
        logger.info("createChildComment:创建子评论" + comment.getFromUid());

        comment.setId(getUUID());
        String parentCommentId = comment.getParentId();
        comment.setCreated(new Date());
        String topicId = comment.getTopicId();
        commentMapper.insertSelective(comment);
        //保存某条评论的 子评论数量，用Hash 保存，当获取某主题的所有评论时候，把子评论的数量一并查询后返回
        // redisTemplate.opsForHash().increment(Constant.CHILD_COMMENT_SIZE + topicId, parentCommentId, 1); 暂时放弃在redis 中存放子评论的数量，因为这样mysql 中没有子评论数量的话，没法根据子评论数量进行排序，
        //增加父评论的子评论据量
        commentMapper.incrementChildCommentSize(parentCommentId);
        //主题ID，作为key,在redis中存储该主题的评论数量，
        // redisTemplate.opsForValue().increment(Constant.COMMENT_SIZE + topicId, 1);

        //增加主题的评论数量
        updateCommentSize(topicId);

        return CommonResult.ok(comment.getId());
    }

    /**
     * 转发捐赠创建子评论
     * @param comment
     * @return
     */
    @Transactional
    @PostMapping("/comment/createChildComment_v1")
    @SerializedField(encrypt = false)
    public CommonResult createForwardChildComment(@RequestBody Comment comment) {
        comment.setId(getUUID());
        String parentCommentId = comment.getParentId();
        comment.setCreated(new Date());
        commentMapper.insertSelective(comment);
        commentMapper.incrementChildCommentSize(parentCommentId);
        //增加转发的评论数量
        forwardMapper.incrementCommentSize(comment.getTopicId());

        return CommonResult.ok(comment.getId());
    }

    @RequestMapping(value = "/comment/get", method = RequestMethod.POST)
    @SerializedField(encrypt = false)
    public CommonResult getComment(@RequestBody Map<String, Object> info) {
        if (!info.containsKey("topicId") || !info.containsKey("uId")) {
            return CommonResult.build(CommonResult.STATUS_FAIL, PARAM_INVALID);
        }
        String topicId = info.get("topicId") + "";
        Object uId = info.get("uId");
        int page = 1;
        int size = 10;
        if (info.containsKey("page")) {
            page = (int) info.get("page");
        }
        if (info.containsKey("size")) {
            size = (int) info.get("size");
        }


        Map<String, Object> result = new HashMap<>();
        //从mysql中查询该主题的评论
        CommentExample example = new CommentExample();
        CommentExample.Criteria criteria = example.createCriteria();
        criteria.andTopicIdEqualTo(topicId);
        criteria.andParentIdIsNull();//这样就不会把子评论 查出来
        example.setOrderByClause("child_size DESC,praise_size DESC");
        PageHelper.startPage(page, size);
        List<Comment> comments = commentMapper.selectByExample(example);
        PageInfo<Comment> commentsPageInfo = new PageInfo<>(comments);
        result.put("comments", commentsPageInfo);
        //第一次查询，需要查询 主题的评论数量、点赞数量 、自己是否给该主题点过赞，子评论数量 ，子评论点赞
        if (page == 1) {

            //查询该主题的点赞数量
            String praiseSize = redisTemplate.opsForValue().get(Constant.TOPIC_PRAISE_SIZE + topicId);
            result.put("praiseSize", praiseSize);
            //查询当前用户是否给这条主题点赞
            Boolean hadPraise = redisTemplate.opsForSet().isMember(Constant.TOPIC_PRAISE_RECORD + topicId, uId);
            result.put("hadPraise", hadPraise);


            //查询评论被点赞的数量
            Map<Object, Object> commentLikeSize = redisTemplate.opsForHash().entries(Constant.COMMENT_PRAISE_SIZE + topicId);
            //如果没有评论被点赞，就直接返回结果，否则就继续判断
            if (commentLikeSize == null || commentLikeSize.size() == 0) {
                return CommonResult.ok(result);
            }
            result.put(CommentConstant.COMMENT_PRAISE_SIZE, commentLikeSize);
            Map<Object, String> praiseRecord = new HashMap<>();
            //keySet返回的是当前主题下、本次查询页中被点过赞的评论的id的集合，下面是遍历这些被点过赞的评论，看是否被自己点过赞，
            for (Object commentId : commentLikeSize.keySet()) {
                Boolean member = redisTemplate.opsForSet().isMember(Constant.COMMENT_PRAISE_RECORD + commentId + "", uId);
                if (member) {
                    praiseRecord.put(commentId, CommentConstant.HAS_ADD_LIKE);
                }
            }
            result.put("praiseRecord", praiseRecord);
        }
        return CommonResult.ok(result);
    }

    private PageInfo<Comment> getComments(String parentCommentId, int page, int size) {
        CommentExample example = new CommentExample();
        CommentExample.Criteria criteria = example.createCriteria();
        criteria.andParentIdEqualTo(parentCommentId);
        PageHelper.startPage(page, size);
        List<Comment> comments = commentMapper.selectByExample(example);
        return new PageInfo<>(comments);
    }

    @RequestMapping(value = "/comment/getChildComment", method = RequestMethod.POST)
    @SerializedField(encrypt = false)
    public CommonResult getChildComment(@RequestBody Map<String, Object> info) {
        if (!info.containsKey("parentId")) {
            return CommonResult.build(CommonResult.STATUS_FAIL, PARAM_INVALID);
        }
        String parentCommentId = info.get("parentId") + "";
        int page = 1;
        int size = 10;
        if (info.containsKey("page")) {
            page = (int) info.get("page");
        }
        if (info.containsKey("size")) {
            size = (int) info.get("size");
        }
        CommentExample example = new CommentExample();
        CommentExample.Criteria criteria = example.createCriteria();
        criteria.andParentIdEqualTo(parentCommentId);
        PageHelper.startPage(page, size);
        List<Comment> comments = commentMapper.selectByExample(example);
        PageInfo<Comment> commentsPageInfo = new PageInfo<>(comments);
        return CommonResult.ok(commentsPageInfo);
    }

    /**
     * 给发布的主题点赞
     *
     * @return
     */
    @RequestMapping(value = "/comment/topicPraise", method = RequestMethod.POST)
    @SerializedField(encrypt = false)
    public CommonResult topicPraise(@RequestBody String topicId) {

        String uId = request.getHeader("uId");

        //  info.put("createDate", new Date());
        // Object likeRecord = info.getTopicById("likeRecord");
        //把当所有被点赞的ip 保存在一个set里面，当把点赞记录批量写入mysql的时候，才能拿到所有的数据，下面两个数据的KEY,都是由topicId组成
        //如果数据就持久化在redis中，而不是要同步进mysql中，那就没必要存这个数据了，所以暂时注销
        // redisTemplate.opsForSet().add(LIKE_TOPIC_ID, topicId);
        //记录每个主题下有哪些人点赞
        redisTemplate.opsForSet().add(Constant.TOPIC_PRAISE_RECORD + topicId, uId);
        //增加点赞数，每次增加1
        redisTemplate.opsForValue().increment(Constant.TOPIC_PRAISE_SIZE + topicId, 1);

        return CommonResult.ok();
    }

    @RequestMapping(value = "/comment/removeTopicPraise", method = RequestMethod.POST)
    @SerializedField(encrypt = false)
    public CommonResult removeTopicPraise(@RequestBody String topicId) {
        String uId = request.getHeader("uId");

        //减少点赞数，每次减少1
        redisTemplate.opsForValue().increment(Constant.TOPIC_PRAISE_SIZE + topicId, new Long("-1"));
        redisTemplate.opsForSet().remove(Constant.TOPIC_PRAISE_RECORD + topicId, uId);

        return CommonResult.ok();
    }

    /**
     * 给某主题下的一条评论点赞
     *
     * @param info
     * @return
     */
    @RequestMapping(value = "/comment/commentPraise", method = RequestMethod.POST)
    @SerializedField(encrypt = false)
    public CommonResult commentPraise(@RequestBody Map<String, Object> info) {
        String uId = request.getHeader("uId");
        String topicId = info.get("topicId") + "";
        String commentId = info.get("commentId") + "";
        //记录某主题下的评论被点赞的数量
        redisTemplate.opsForHash().increment(Constant.COMMENT_PRAISE_SIZE + topicId, commentId, 1);
        //记录某评论下有那些人点了赞
        redisTemplate.opsForSet().add(Constant.COMMENT_PRAISE_RECORD + commentId, uId);
        return CommonResult.ok();
    }

    /**
     * 去除评论点赞
     *
     * @return
     */
    @RequestMapping(value = "/comment/removeCommentPraise", method = RequestMethod.POST)
    @SerializedField(encrypt = false)
    public CommonResult removeCommentPraise(@RequestBody Map<String, Object> info) {
        String uId = request.getHeader("uId");
        String topicId = info.get("topicId") + "";
        String commentId = info.get("commentId") + "";
        //把评论点赞的数量减去1
        redisTemplate.opsForHash().increment(Constant.COMMENT_PRAISE_SIZE + topicId, commentId, -1);
        //从评论点赞set中删除用户id
        redisTemplate.opsForSet().remove(Constant.COMMENT_PRAISE_RECORD + commentId, uId);
        return CommonResult.ok();
    }

    @PostMapping("/comment/accusationComment")
    public CommonResult accusationComment(@RequestBody String commentId) {
        String uId = request.getHeader("uId");

        logger.warn("accusation:uId:" + uId + "  commentId:" + commentId);
        Comment comment = new Comment();
        comment.setId(commentId);
        comment.setStatus(Constant.TYPE_ACCUSATION);
        commentMapper.updateByPrimaryKeySelective(comment);
        return CommonResult.ok();
    }

    private String getUUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }
}
